package org.quartz;

import java.util.Date;
import java.util.List;
import java.util.Set;

import org.quartz.spi.JobFactory;

public interface Scheduler {

	String DEFAULT_GROUP = "DEFAULT";

	String DEFAULT_MANUAL_TRIGGERS = "MANUAL_TRIGGER";

	/**
	 * <p>
	 * A constant <code>Trigger</code> group name used internally by the scheduler -
	 * clients should not use the value of this constant ("RECOVERING_JOBS") for the
	 * name of a <code>Trigger</code>'s group.
	 * </p>
	 *
	 * @see org.quartz.JobDetail#requestsRecovery()
	 */
	String DEFAULT_RECOVERY_GROUP = "RECOVERING_JOBS";

	/**
	 * <p>
	 * A constant <code>Trigger</code> group name used internally by the scheduler -
	 * clients should not use the value of this constant ("FAILED_OVER_JOBS") for
	 * the name of a <code>Trigger</code>'s group.
	 * </p>
	 *
	 * @see org.quartz.JobDetail#requestsRecovery()
	 */
	String DEFAULT_FAIL_OVER_GROUP = "FAILED_OVER_JOBS";

	/**
	 * A constant <code>JobDataMap</code> key that can be used to retrieve the name
	 * of the original <code>Trigger</code> from a recovery trigger's data map in
	 * the case of a job recovering after a failed scheduler instance.
	 *
	 * @see org.quartz.JobDetail#requestsRecovery()
	 */
	String FAILED_JOB_ORIGINAL_TRIGGER_NAME = "QRTZ_FAILED_JOB_ORIG_TRIGGER_NAME";

	/**
	 * A constant <code>JobDataMap</code> key that can be used to retrieve the group
	 * of the original <code>Trigger</code> from a recovery trigger's data map in
	 * the case of a job recovering after a failed scheduler instance.
	 *
	 * @see org.quartz.JobDetail#requestsRecovery()
	 */
	String FAILED_JOB_ORIGINAL_TRIGGER_GROUP = "QRTZ_FAILED_JOB_ORIG_TRIGGER_GROUP";

	/**
	 * A constant <code>JobDataMap</code> key that can be used to retrieve the
	 * scheduled fire time of the original <code>Trigger</code> from a recovery
	 * trigger's data map in the case of a job recovering after a failed scheduler
	 * instance.
	 *
	 * @see org.quartz.JobDetail#requestsRecovery()
	 */
	String FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS = "QRTZ_FAILED_JOB_ORIG_TRIGGER_FIRETIME_IN_MILLISECONDS_AS_STRING";

	/*
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 * 
	 * Interface.
	 * 
	 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	 */

	/**
	 * <p>
	 * Returns the name of the <code>Scheduler</code>.
	 * </p>
	 */
	String getSchedulerName() throws SchedulerException;

	/**
	 * <p>
	 * Returns the instance Id of the <code>Scheduler</code>.
	 * </p>
	 */
	String getSchedulerInstanceId() throws SchedulerException;

	/**
	 * <p>
	 * Returns the <code>SchedulerContext</code> of the <code>Scheduler</code>.
	 * </p>
	 */
	SchedulerContext getContext() throws SchedulerException;

	///////////////////////////////////////////////////////////////////////////
	///
	/// Scheduler State Management Methods
	///
	///////////////////////////////////////////////////////////////////////////

	void start() throws SchedulerException;

	void startDelayed(int seconds) throws SchedulerException;

	boolean isStarted() throws SchedulerException;

	void standby() throws SchedulerException;

	boolean isInStandbyMode() throws SchedulerException;

	void shutdown() throws SchedulerException;

	void shutdown(boolean waitForJobsToComplete) throws SchedulerException;

	boolean isShutdown() throws SchedulerException;

	SchedulerMetaData getMetaData() throws SchedulerException;

	List getCurrentlyExecutingJobs() throws SchedulerException;

	void setJobFactory(JobFactory factory) throws SchedulerException;

	///////////////////////////////////////////////////////////////////////////
	///
	/// Scheduling-related Methods
	///
	///////////////////////////////////////////////////////////////////////////

	Date scheduleJob(JobDetail jobDetail, Trigger trigger) throws SchedulerException;

	Date scheduleJob(Trigger trigger) throws SchedulerException;

	/**
	 * <p>
	 * Remove the indicated <code>{@link Trigger}</code> from the scheduler.
	 * </p>
	 */
	boolean unscheduleJob(String triggerName, String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Remove (delete) the <code>{@link org.quartz.Trigger}</code> with the given
	 * name, and store the new given one - which must be associated with the same
	 * job (the new trigger must have the job name & group specified) - however, the
	 * new trigger need not have the same name as the old trigger.
	 * </p>
	 * 
	 * @param triggerName The name of the <code>Trigger</code> to be replaced.
	 * @param groupName   The group name of the <code>Trigger</code> to be replaced.
	 * @param newTrigger  The new <code>Trigger</code> to be stored.
	 * @return <code>null</code> if a <code>Trigger</code> with the given name &
	 *         group was not found and removed from the store, otherwise the first
	 *         fire time of the newly scheduled trigger.
	 */
	Date rescheduleJob(String triggerName, String groupName, Trigger newTrigger) throws SchedulerException;

	void addJob(JobDetail jobDetail, boolean replace) throws SchedulerException;

	boolean deleteJob(String jobName, String groupName) throws SchedulerException;

	void triggerJob(String jobName, String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Trigger the identified <code>{@link org.quartz.JobDetail}</code> (execute it
	 * now) - the generated trigger will be volatile.
	 * </p>
	 */
	void triggerJobWithVolatileTrigger(String jobName, String groupName) throws SchedulerException;

	void triggerJob(String jobName, String groupName, JobDataMap data) throws SchedulerException;

	void triggerJobWithVolatileTrigger(String jobName, String groupName, JobDataMap data) throws SchedulerException;

	void pauseJob(String jobName, String groupName) throws SchedulerException;

	void pauseJobGroup(String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Pause the <code>{@link Trigger}</code> with the given name.
	 * </p>
	 * 
	 * @see #resumeTrigger(String, String)
	 */
	void pauseTrigger(String triggerName, String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Pause all of the <code>{@link Trigger}s</code> in the given group.
	 * </p>
	 * 
	 * <p>
	 * The Scheduler will "remember" that the group is paused, and impose the pause
	 * on any new triggers that are added to the group while the group is paused.
	 * </p>
	 * 
	 * @see #resumeTriggerGroup(String)
	 */
	void pauseTriggerGroup(String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Resume (un-pause) the <code>{@link org.quartz.JobDetail}</code> with the
	 * given name.
	 * </p>
	 * 
	 * <p>
	 * If any of the <code>Job</code>'s<code>Trigger</code> s missed one or more
	 * fire-times, then the <code>Trigger</code>'s misfire instruction will be
	 * applied.
	 * </p>
	 * 
	 * @see #pauseJob(String, String)
	 */
	void resumeJob(String jobName, String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Resume (un-pause) all of the <code>{@link org.quartz.JobDetail}s</code> in
	 * the given group.
	 * </p>
	 * 
	 * <p>
	 * If any of the <code>Job</code> s had <code>Trigger</code> s that missed one
	 * or more fire-times, then the <code>Trigger</code>'s misfire instruction will
	 * be applied.
	 * </p>
	 * 
	 * @see #pauseJobGroup(String)
	 */
	void resumeJobGroup(String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Resume (un-pause) the <code>{@link Trigger}</code> with the given name.
	 * </p>
	 * 
	 * <p>
	 * If the <code>Trigger</code> missed one or more fire-times, then the
	 * <code>Trigger</code>'s misfire instruction will be applied.
	 * </p>
	 * 
	 * @see #pauseTrigger(String, String)
	 */
	void resumeTrigger(String triggerName, String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Resume (un-pause) all of the <code>{@link Trigger}s</code> in the given
	 * group.
	 * </p>
	 * 
	 * <p>
	 * If any <code>Trigger</code> missed one or more fire-times, then the
	 * <code>Trigger</code>'s misfire instruction will be applied.
	 * </p>
	 * 
	 * @see #pauseTriggerGroup(String)
	 */
	void resumeTriggerGroup(String groupName) throws SchedulerException;

	void pauseAll() throws SchedulerException;

	void resumeAll() throws SchedulerException;

	String[] getJobGroupNames() throws SchedulerException;

	String[] getJobNames(String groupName) throws SchedulerException;

	Trigger[] getTriggersOfJob(String jobName, String groupName) throws SchedulerException;

	String[] getTriggerGroupNames() throws SchedulerException;

	String[] getTriggerNames(String groupName) throws SchedulerException;

	/**
	 * <p>
	 * Get the names of all <code>{@link Trigger}</code> groups that are paused.
	 * </p>
	 */
	Set getPausedTriggerGroups() throws SchedulerException;

	/**
	 * <p>
	 * Get the <code>{@link JobDetail}</code> for the <code>Job</code> instance with
	 * the given name and group.
	 * </p>
	 */
	JobDetail getJobDetail(String jobName, String jobGroup) throws SchedulerException;

	/**
	 * <p>
	 * Get the <code>{@link Trigger}</code> instance with the given name and group.
	 * </p>
	 */
	Trigger getTrigger(String triggerName, String triggerGroup) throws SchedulerException;

	/**
	 * <p>
	 * Get the current state of the identified <code>{@link Trigger}</code>.
	 * </p>
	 * 
	 * @see Trigger#STATE_NORMAL
	 * @see Trigger#STATE_PAUSED
	 * @see Trigger#STATE_COMPLETE
	 * @see Trigger#STATE_ERROR
	 * @see Trigger#STATE_BLOCKED
	 * @see Trigger#STATE_NONE
	 */
	int getTriggerState(String triggerName, String triggerGroup) throws SchedulerException;

	/**
	 * <p>
	 * Add (register) the given <code>Calendar</code> to the Scheduler.
	 * </p>
	 * 
	 * @param updateTriggers whether or not to update existing triggers that
	 *                       referenced the already existing calendar so that they
	 *                       are 'correct' based on the new trigger.
	 * 
	 * 
	 * @throws SchedulerException if there is an internal Scheduler error, or a
	 *                            Calendar with the same name already exists, and
	 *                            <code>replace</code> is <code>false</code>.
	 */
	void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)
			throws SchedulerException;

	/**
	 * <p>
	 * Delete the identified <code>Calendar</code> from the Scheduler.
	 * </p>
	 * 
	 * @return true if the Calendar was found and deleted.
	 * @throws SchedulerException if there is an internal Scheduler error.
	 */
	boolean deleteCalendar(String calName) throws SchedulerException;

	/**
	 * <p>
	 * Get the <code>{@link Calendar}</code> instance with the given name.
	 * </p>
	 */
	Calendar getCalendar(String calName) throws SchedulerException;

	String[] getCalendarNames() throws SchedulerException;

	boolean interrupt(String jobName, String groupName) throws UnableToInterruptJobException;

	///////////////////////////////////////////////////////////////////////////
	///
	/// Listener-related Methods
	///
	///////////////////////////////////////////////////////////////////////////

	void addGlobalJobListener(JobListener jobListener) throws SchedulerException;

	void addJobListener(JobListener jobListener) throws SchedulerException;

	boolean removeGlobalJobListener(String name) throws SchedulerException;

	boolean removeJobListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Get a List containing all of the <code>{@link JobListener}</code> s in the
	 * <code>Scheduler</code>'s<i>global</i> list.
	 * </p>
	 * 
	 * @see #addGlobalJobListener(JobListener)
	 */
	List getGlobalJobListeners() throws SchedulerException;

	/**
	 * <p>
	 * Get a Set containing the names of all the
	 * <i>non-global</i><code>{@link JobListener}</code> s registered with the
	 * <code>Scheduler</code>.
	 * </p>
	 * 
	 * @see #addJobListener(JobListener)
	 */
	Set getJobListenerNames() throws SchedulerException;

	/**
	 * <p>
	 * Get the <i>global</i><code>{@link JobListener}</code> that has the given
	 * name.
	 * </p>
	 * 
	 * @see #addGlobalJobListener(JobListener)
	 */
	JobListener getGlobalJobListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Get the <i>non-global</i><code>{@link JobListener}</code> that has the given
	 * name.
	 * </p>
	 * 
	 * @see #addJobListener(JobListener)
	 */
	JobListener getJobListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Add the given <code>{@link TriggerListener}</code> to the
	 * <code>Scheduler</code>'s <i>global</i> list.
	 * </p>
	 * 
	 * <p>
	 * Listeners in the 'global' list receive notification of execution events for
	 * ALL <code>{@link Trigger}</code>s.
	 * </p>
	 * 
	 * <p>
	 * Global listeners receive events for ALL triggers, and non-global listeners
	 * receive events only for the specific triggers that explicitly name the
	 * listener in the {@link Trigger#getTriggerListenerNames()} property.
	 * </p>
	 * 
	 * @see #addTriggerListener(TriggerListener)
	 */
	void addGlobalTriggerListener(TriggerListener triggerListener) throws SchedulerException;

	/**
	 * <p>
	 * Add the given <code>{@link TriggerListener}</code> to the
	 * <code>Scheduler</code>'s list, of registered <code>TriggerListener</code>s.
	 * 
	 * <p>
	 * Global listeners receive events for ALL triggers, and non-global listeners
	 * receive events only for the specific triggers that explicitly name the
	 * listener in the {@link Trigger#getTriggerListenerNames()} property.
	 * </p>
	 * 
	 * @see #addGlobalTriggerListener(TriggerListener)
	 */
	void addTriggerListener(TriggerListener triggerListener) throws SchedulerException;

	/**
	 * <p>
	 * Remove the identified <code>{@link TriggerListener}</code> from the
	 * <code>Scheduler</code>'s list of <i>global</i> listeners.
	 * </p>
	 * 
	 * @return true if the identified listener was found in the list, and removed.
	 * 
	 * @see #addGlobalTriggerListener(TriggerListener)
	 */
	boolean removeGlobalTriggerListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Remove the identified <code>{@link TriggerListener}</code> from the
	 * <code>Scheduler</code>'s list of registered listeners.
	 * </p>
	 * 
	 * @return true if the identified listener was found in the list, and removed.
	 * 
	 * @see #addTriggerListener(TriggerListener)
	 */
	boolean removeTriggerListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Get a List containing all of the <code>{@link TriggerListener}</code> s in
	 * the <code>Scheduler</code>'s<i>global</i> list.
	 * </p>
	 * 
	 * @see #addGlobalTriggerListener(TriggerListener)
	 */
	List getGlobalTriggerListeners() throws SchedulerException;

	/**
	 * <p>
	 * Get a Set containing the names of all the
	 * <i>non-global</i><code>{@link TriggerListener}</code> s registered with the
	 * <code>Scheduler</code>.
	 * </p>
	 * 
	 * @see #addTriggerListener(TriggerListener)
	 */
	Set getTriggerListenerNames() throws SchedulerException;

	/**
	 * <p>
	 * Get the <i>global</i><code>{@link TriggerListener}</code> that has the given
	 * name.
	 * </p>
	 * 
	 * @see #addGlobalTriggerListener(TriggerListener)
	 */
	TriggerListener getGlobalTriggerListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Get the <i>non-global</i><code>{@link TriggerListener}</code> that has the
	 * given name.
	 * </p>
	 * 
	 * @see #addTriggerListener(TriggerListener)
	 */
	TriggerListener getTriggerListener(String name) throws SchedulerException;

	/**
	 * <p>
	 * Register the given <code>{@link SchedulerListener}</code> with the
	 * <code>Scheduler</code>.
	 * </p>
	 */
	void addSchedulerListener(SchedulerListener schedulerListener) throws SchedulerException;

	/**
	 * <p>
	 * Remove the given <code>{@link SchedulerListener}</code> from the
	 * <code>Scheduler</code>.
	 * </p>
	 * 
	 * @return true if the identified listener was found in the list, and removed.
	 */
	boolean removeSchedulerListener(SchedulerListener schedulerListener) throws SchedulerException;

	/**
	 * <p>
	 * Get a List containing all of the <code>{@link SchedulerListener}</code> s
	 * registered with the <code>Scheduler</code>.
	 * </p>
	 */
	List getSchedulerListeners() throws SchedulerException;

}
